#include <cutil_inline.h>
#include "config.cuh"

#define MODE 0
#if MODE==0
#define N 10000
#define DATAFILE "data.txt.origin"
#else
#define N 1000000
#define DATAFILE "data.txt.100w"
#endif
#define CSC 10*N

void parseData(string rec, int* closeSetCount, int i, ha_t* ha)
{
	char * cstr, *p;
	cstr = new char[rec.size()+1];
	strcpy(cstr, rec.c_str());

	float pos = 0, duration = 0, speed = 0, time = 0;
	int baseId = 0, no = 0, etype = 0;

#if MODE ==0
	p=strtok (cstr,"\t");
	no = atoi(p); //no
	p=strtok(NULL,"\t");
	time = (float)atof(p);//time
	p=strtok(NULL,"\t");
	baseId = atoi(p)-1; //baseid
	pos = baseId*2+1;//pos
	p=strtok(NULL,"\t");
	duration = (float)atof(p);//duration
	p=strtok(NULL,"\t");
	speed = (float)atof(p);//speed
	etype=INIT;
#else
	p=strtok (cstr,"\t");
	no = atoi(p); //no
	p=strtok(NULL,"\t");
	time = (float)atof(p);//time
	p=strtok(NULL,"\t");
	duration = (float)atof(p);//duration
	p=strtok(NULL,"\t");
	pos = (float)atof(p);//pos
	baseId = (int)(pos/2);//baseid
	p=strtok(NULL,"\t");
	speed = (float)atof(p);//speed
	etype=INIT;
#endif

	int endBaseId;
	if(pos+duration*speed/3600>40)
		endBaseId=19;
	else
		endBaseId=(pos+duration*speed/3600)/2;

	ha->h_init[i]=*closeSetCount;
	ha->h_baseId[*closeSetCount]=baseId;
	ha->h_duration[*closeSetCount]=duration;
	ha->h_etype[*closeSetCount]=etype;
	ha->h_no[*closeSetCount]=no;
	ha->h_pos[*closeSetCount]=pos;
	ha->h_speed[*closeSetCount]=speed;
	ha->h_time[*closeSetCount]=time;
	*closeSetCount+=((endBaseId-baseId)*2+2);
}

int init(ha_t* ha, da_t* da)
{
	ifstream fin;
	fin.open(DATAFILE);
	string rec;

	ha->h_baseId = (int*)malloc(CSC*sizeof(int));
	ha->h_duration = (float*)malloc(CSC*sizeof(float));
	ha->h_speed = (float*)malloc(CSC*sizeof(float));
	ha->h_pos = (float*)malloc(CSC*sizeof(float));
	ha->h_no = (int*)malloc(CSC*sizeof(int));
	ha->h_time = (float*)malloc(CSC*sizeof(float));
	ha->h_etype = (int*)malloc(CSC*sizeof(int));
	ha->h_init = (int*)malloc(N*sizeof(int));

	int i = 0;
	int counter = 0;
	while(!fin.eof()){
		getline(fin,rec);
		parseData(rec, &counter, i, ha);
		i++;
	}
	fin.close();

	cudaMalloc((void**)&(da->d_index),counter*sizeof(int));
	cudaMalloc((void**)&(da->d_baseId), counter*sizeof(int));
	cudaMalloc((void**)&(da->d_time),counter*sizeof(float));
	cudaMalloc((void**)&(da->d_duration), counter*sizeof(float));
	cudaMalloc((void**)&(da->d_speed), counter*sizeof(float));
	cudaMalloc((void**)&(da->d_pos), counter*sizeof(float));
	cudaMalloc((void**)&(da->d_no), counter*sizeof(int));
	cudaMalloc((void**)&(da->d_etype), counter*sizeof(int));
	cudaMalloc((void**)&(da->d_init), N*sizeof(int));

	cudaMemcpy(da->d_time, ha->h_time, counter*sizeof(int), cudaMemcpyHostToDevice);
	cudaMemcpy(da->d_baseId,ha->h_baseId,counter*sizeof(int),cudaMemcpyHostToDevice);
	cudaMemcpy(da->d_duration,ha->h_duration,counter*sizeof(float),cudaMemcpyHostToDevice);
	cudaMemcpy(da->d_speed,ha->h_speed,counter*sizeof(float),cudaMemcpyHostToDevice);
	cudaMemcpy(da->d_pos,ha->h_pos,counter*sizeof(float),cudaMemcpyHostToDevice);
	cudaMemcpy(da->d_no,ha->h_no,counter*sizeof(int),cudaMemcpyHostToDevice);
	cudaMemcpy(da->d_etype,ha->h_etype,counter*sizeof(int),cudaMemcpyHostToDevice);
	cudaMemcpy(da->d_init,ha->h_init, N*sizeof(int), cudaMemcpyHostToDevice);

	free(ha->h_time);
	free(ha->h_baseId);
	free(ha->h_duration);
	free(ha->h_speed);
	free(ha->h_pos);
	free(ha->h_no);
	free(ha->h_etype);
	free(ha->h_init);

	return counter;
}

/*memcpy in launch kernel and main produce different effects possibly because
the extern indentifier*/
extern "C" void launch_init_kernel(da_t da, int count);
extern "C" void launch_sort_kernel(da_t &da, int count);
extern "C" void launch_separation_kernel(da_t da, int count, int *seps);
extern "C" void launch_sum_kernel(da_t da, int count, int ptr);
extern "C" int  launch_correction_kernel(da_t da, int base_n, int count, int ptr);
extern "C" int  launch_big_correction_kernel(da_t da, int n);
extern "C" int	getRes();


int main(int argc, char** argv)
{
	CUevent start, stop;
	CUevent start_o, stop_o; //overall
	float elapsedTime=0;

	timer_start(start_o, stop_o);

	ha_t ha;
	da_t da;

	//INIT_HOST
	int counter = init(&ha, &da);
	cout<<counter<<endl;
	
	//INIT_kernel after this process, d_speed, d_pos, d_duration, d_init is freed
	launch_init_kernel(da, N);

	//SORT_KERNEL after this process, d_time, d_index is freed
	launch_sort_kernel(da, counter);
	
	cout<<"overall:\t";
	timer_stop(start_o, stop_o, elapsedTime);
	cout<<getRes();
}